package holmes

import (
	"errors"
	"fmt"
	"os"
	"path"
	"sync"
	"sync/atomic"
	"time"
)

const DefaultMaxPrintNum = 1000

type logSegmentNumLimit struct {
	// 64bit atomic vars need to be first for proper alignment on 32bit platforms
	CurrentNum    int64
	PrintNumLimit int64 //打印条数限制

	logPath string
	logFile *os.File

	ReCreateLock sync.Mutex
}

func (ls *logSegmentNumLimit) setting(logPath string, limit int64) error {
	if logPath != "" {
		err := os.MkdirAll(logPath, os.ModePerm)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return err
		}
		name := getLogFileName(time.Now())
		logFileName := path.Join(logPath, name)
		logFile, err := os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			if os.IsNotExist(err) {
				logFile, err = os.Create(logFileName)
				if err != nil {
					fmt.Fprintln(os.Stderr, err)
					return err
				}
			} else {
				fmt.Fprintln(os.Stderr, err)
				return err
			}
		}
		link_name := getLogFileLinkName()
		log_link_name := path.Join(logPath, link_name)
		os.Remove(log_link_name)
		err = os.Symlink(name, log_link_name)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if limit == 0 {
			limit = DefaultMaxPrintNum
		}
		ls.logFile = logFile
		ls.logPath = logPath
		ls.PrintNumLimit = limit
		return nil
	}
	return errors.New("文件名不能为空")
}
func (ls *logSegmentNumLimit) Write(p []byte) (n int, err error) {
	value := atomic.LoadInt64(&ls.CurrentNum)
	if value >= ls.PrintNumLimit {
		ls.ReCreateLock.Lock()
		defer ls.ReCreateLock.Unlock()
		//重新读出 原因是该函数可能被同时多次调用，而重新创建只需第一个完成
		value = atomic.LoadInt64(&ls.CurrentNum)
		if value >= ls.PrintNumLimit {
			//清空数目
			atomic.AddInt64(&ls.CurrentNum, -1*value)
			//清空文件
			fmt.Printf("文件行数超出%s 行数%d\n", ls.logFile.Name(), value)
			ls.logFile.Close()
			os.Remove(ls.logFile.Name())
			ls.logFile = nil
			//创建新的文件
			name := getLogFileName(time.Now())
			ls.logFile, err = os.Create(path.Join(ls.logPath, name))
			if err != nil {
				// log into stderr if we can't create new file
				fmt.Fprintln(os.Stderr, err)
				ls.logFile = os.Stderr
			}
			//建立新的文件链接以便获取该文件
			link_name := getLogFileLinkName()
			log_link_name := path.Join(ls.logPath, link_name)
			os.Remove(log_link_name)
			err = os.Symlink(name, log_link_name)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		} else {
			//竞争失败
			fmt.Printf("进入临界")
		}

	}
	atomic.AddInt64(&ls.CurrentNum, 1)

	return ls.logFile.Write(p)
}
func (ls *logSegmentNumLimit) Close() error {
	if ls.logFile != nil {
		return ls.logFile.Close()
	}
	return nil
}

func getLogFileName(t time.Time) string {
	proc := path.Base(os.Args[0])
	now := time.Now()
	year := now.Year()
	month := now.Month()
	day := now.Day()
	hour := now.Hour()
	minute := now.Minute()
	pid := os.Getpid()
	return fmt.Sprintf("%s.%04d-%02d-%02d-%02d-%02d.%d.log",
		proc, year, month, day, hour, minute, pid)
}
func getLogFileLinkName() string {
	return path.Base(os.Args[0]) + ".log"
}

//文件输出模式
type fileManagement struct {
	logSegmentNumLimit
}

func (l *fileManagement) GetFileSize() int64 {
	if l.logFile != nil {
		state, err := l.logFile.Stat()
		if err != nil {
			loggerInstance.doPrintf(ERROR, "获取文件大小错误")
			return 0
		}
		return state.Size()
	}
	return 0
}
func (l *fileManagement) GetFileName() (string, bool) {
	if l.logFile != nil {
		return l.logFile.Name(), true
	}
	return "", false
}
func (l *fileManagement) config(settings map[string]interface{}) error {
	var logPath string
	var limit int64
	//一旦出现错误,停止设置
	for key, value := range settings {
		switch key {
		case "文件大小限制":
			if true_value, ok := value.(int64); ok {
				limit = true_value
			} else {
				return errors.New("文件大小限制格式错误,需求为int64")
			}
		case "文件保存路径":
			if true_value, ok := value.(string); ok {
				logPath = true_value
			} else {
				return errors.New("文件保存路径格式错误,需求为string")
			}
		}
	}
	l.setting(logPath, limit)
	return nil
}
func (l fileManagement) mode() IoWriterMode {
	return IoWriterFileMode
}

// LogFilePath returns a function to set the log file path.
func SetFileModeArgs(road string, limit int64) func(Logger) Logger {
	args := map[string]interface{}{
		"文件大小限制": limit,
		"文件保存路径": road}
	return func(l Logger) Logger {
		//未初始化时
		if l.writesManagement == nil {
			l.writesManagement = new(fileManagement)
			l.config(args)
		}
		switch l.mode() {
		//文件模式
		case IoWriterStdFileMode:
			fallthrough
		case IoWriterFileMode:
			l.config(args)
		default: //现有模式不符合条件
			l.writesManagement = new(fileManagement)
			l.config(args)

		}
		return l
	}
}

type stdWithFileMode struct {
	fileManagement
}

func (two *stdWithFileMode) Write(p []byte) (n int, err error) {
	os.Stderr.Write(p)
	return two.fileManagement.Write(p)
}
func (two *stdWithFileMode) config(settings map[string]interface{}) error {
	return two.fileManagement.config(settings)
}
func (two *stdWithFileMode) mode() IoWriterMode {
	return IoWriterStdFileMode
}
func SetStdBlendFile(road string, limit int64) func(Logger) Logger {
	args := map[string]interface{}{
		"文件大小限制": limit,
		"文件保存路径": road}
	return func(l Logger) Logger {
		l.writesManagement = new(stdWithFileMode)
		l.config(args)
		return l
	}
}
